package cloud.xiangyixiang.www.spring.boot.java.basics.controller;

import org.springframework.web.bind.annotation.RestController;

/**
 * <p>
 * JAVA 装箱和拆箱。
 * </p>
 *
 *  简单一点说，装箱就是  自动将基本数据类型转换为引用类型；拆箱就是自动将引用类型转换为基本数据类型。
 *
 * @author zhixinglu
 * @date 2023/8/31 20:35
 */
@RestController
public class BoxingAndUnboxingController {

    public static void main(String[] args) {

        // 1. 描述介绍
        description();

        // 2. 举例
        unboxing();

        // 3. 面试题
        interviewInteger();
        interviewBaseType();
    }

    /**
     * 描述介绍
     */
    private static void description(){
        System.out.println("描述介绍：=======================");
        String question1 = "Q1: 总结装箱和拆箱的实现过程? ";
        String answer1 = "A1: 装箱过程是通过调用包装器的valueOf方法实现的，而拆箱过程是通过引用类型调用xxxValue实现的。";

        System.out.println(question1 + " ");
        System.out.println(answer1);


        String description1 = "整型：\n" +
                "byte：-2^7 ~ 2^7-1，即-128 ~ 127。1字节。Byte。末尾加B \n" +
                "short：-2^15 ~ 2^15-1，即-32768 ~ 32767。2字节。Short。末尾加S \n" +
                "int：-2^31 ~ 2^31-1，即-2147483648 ~ 2147483647。4字节。Integer。 \n" +
                "long：-2^63 ~ 2^63-1，即-9223372036854774808 ~ 9223372036854774807。8字节。Long。末尾加L。（也可以不加L）";

        String description2 = "浮点型：\n " +
                "float：4字节。Float。\n" +
                "double：8字节。Double。";

        String description3 = "字符型：\n" +
                "char：2字节。Character。";

        String description4 = "布尔型：\n" +
                "boolean：Boolean。";

        String description5 = "类型转换：\n" +
                "boolean类型与其他基本类型不能进行类型的转换（既不能进行自动类型的提升，也不能强制类型转换）， 否则，将编译出错。\n" +
                "byte型不能自动类型提升到char，char和short直接也不会发生自动类型提升（因为负数的问题），同时，byte当然可以直接提升到short型。\n" +
                "当对小于int的数据类型（byte, char, short）进行运算时，首先会把这些类型的变量值强制转为int类型进行计算，最后会得到int类型的值。因此，如果把2个short类型的值相加，最后得到的结果是int类型，如果需要得到short类型的结果，就必须显示地运算结果转为short类型。";

        System.out.println(description1);
        System.out.println(description2);
        System.out.println(description3);
        System.out.println(description4);
        System.out.println(description5);

        System.out.println();
    }

    /**
     * 装箱过程是通过调用包装器的valueOf方法实现的，而拆箱过程是通过引用类型调用xxxValue实现的。
     */
    private static void unboxing(){
        // 装箱
        System.out.println("装箱：Integer i = 10;");
        // 拆箱
        System.out.println("拆箱：int n = i;");
        System.out.println();
    }

    /**
     * 面试题1
     *
     * 下面这段代码的输出结果是什么？
     */
    public static void interviewInteger(){
        Integer i1 = 100;
        Integer i2 = 100;
        Integer i3 = 200;
        Integer i4 = 200;

        // true
        System.out.println("eg1: Integer i1 = 100; Integer i2 = 100; \n" +
                "     i1==i2 result: " + (i1==i2));

        // false
        System.out.println("eg2: Integer i3 = 200; Integer i4 = 200; \n" +
                "     i3==i4 result: " + (i3==i4));

        System.out.println("引用类型：比较的就是地址值是否相同");

        System.out.println("通过valueOf方法创建Integer对象的时候，如果数值在[-128,127]之间，便返回指向IntegerCache.cache中已经存在的对象的引用；否则创建一个新的Integer对象。");

        System.out.println("其它的引用类型，可以去查看valueOf的实现");

        System.out.println();
    }

    /**
     * 面试题基础类型
     */
    public static void interviewBaseType(){
        Integer a = 1;
        Integer b = 2;
        Integer c = 3;
        Integer d = 3;
        Integer e = 321;
        Integer f = 321;
        Long g = 3L;
        Long h = 2L;

        // true -128~127 地址值相同
        System.out.println("eg1: " +
                "Integer c = 3; Integer d = 3; \n" +
                "     c == d result: " + (c==d));

        // false 地址不同
        System.out.println("eg2: Integer e = 321; Integer f = 321; \n" +
                "     c == d result: " + (e==f));

        // true
        // a+b包含了算术运算，因此会触发自动拆箱过程（会调用intValue方法），因此它们比较的是数值是否相等
        System.out.println("eg3: Integer a = 1; Integer b = 2; Integer c = 3; \n" +
                "     c==(a+b) result: " + (c==(a+b)));

        // true
        // c.equals(a+b)会先触发自动拆箱过程，再触发自动装箱过程，也就是说a+b，会先各自调用intValue方法，得到了加法运算后的数值之后，便调用Integer.valueOf方法，再进行equals比较
        System.out.println("eg4: Integer a = 1; Integer b = 2; Integer c = 3; \n" +
                "     c.equals(a+b) result: " + (c.equals(a+b)));

        // true
        System.out.println("eg5: Integer a = 1; Integer b = 2; Long g = 3L; \n" +
                "     g==(a+b) result: " + (g==(a+b)));
        // false 类型不同
        // 如果数值是int类型的，装箱过程调用的是Integer.valueOf；如果是long类型的，装箱调用的Long.valueOf方法
        System.out.println("eg6: Integer a = 1; Integer b = 2; Long g = 3L; \n" +
                "     g.equals(a+b) result: " + (g.equals(a+b)));


        // true 类型不同
        // 如果数值是int类型的，装箱过程调用的是Integer.valueOf；如果是long类型的，装箱调用的Long.valueOf方法
        System.out.println("eg7: Integer a = 1; Long g = 3L; Long h = 2L; \n" +
                "     g.equals(a+h) result: " + (g.equals(a+h)));


        System.out.println();
    }

}
